﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DanielVaughan.Logging;
using System.Windows.Threading;
using SLControlLibrary;
using System.Collections.Generic;

namespace ThreadSafeLog
{
    public class Log : ILog, UIObjects.ILog
    {
        public event EventHandler<InternalMessageEventArgs> InternalMessage;
        public event EventHandler<LogEventArgs> LogEntrySent;
        public event EventHandler<LogEventArgs> WriteRequested;
        public event EventHandler<UIObjects.InternalMessageEventArgs> InterfaceInternalMessage;
        public event EventHandler<UIObjects.LogEventArgs> InterfaceLogEntrySent;
        public event EventHandler<UIObjects.LogEventArgs> InterfaceWriteRequested;
        private UIThread uiThread;
        private ILog log;
        public static bool Enabled { get; set; }

        public Log(UserControl page)
        {
            uiThread = new UIThread(page.Dispatcher);
            log = LogManager.GetLog(page.GetType());

            log.InternalMessage += (sender, e) =>
            {
                if (InternalMessage != null)
                {
                    InternalMessage(sender, e);
                }

                if (InterfaceInternalMessage != null)
                {
                    InterfaceInternalMessage(sender, new UIObjects.InternalMessageEventArgs(e.Message, e.Exception));
                }
            };

            log.LogEntrySent += (sender, e) =>
            {
                if (LogEntrySent != null)
                {
                    LogEntrySent(sender, e);
                }

                if (InterfaceLogEntrySent != null)
                {
                    var logEntryData = new UIObjects.LogEntryData
                    {
                        Message = e.LogEntryData.Message,
                        OccuredAt = e.LogEntryData.OccuredAt,
                        LogLevel = (UIObjects.LogLevel) e.LogEntryData.LogLevel,
                        CodeLocation = new UIObjects.CodeLocation
                        {
                            ClassName = e.LogEntryData.CodeLocation.ClassName,
                            FileName = e.LogEntryData.CodeLocation.FileName,
                            LineNumber = e.LogEntryData.CodeLocation.LineNumber,
                            MethodName = e.LogEntryData.CodeLocation.MethodName
                        },
                        ManagedThreadId = e.LogEntryData.ManagedThreadId,
                        Properties = e.LogEntryData.Properties
                    };

                    if (e.LogEntryData.ExceptionMemento != null)
                    {
                        logEntryData.ExceptionMemento = new UIObjects.ExceptionMemento
                        {
                            Message = e.LogEntryData.ExceptionMemento.Message,
                            Source = e.LogEntryData.ExceptionMemento.Source,
                            TypeName = e.LogEntryData.ExceptionMemento.TypeName,
                            StackTrace = e.LogEntryData.ExceptionMemento.StackTrace
                        };
                    }

                    InterfaceLogEntrySent(sender, new UIObjects.LogEventArgs(logEntryData));
                }
            };

            log.WriteRequested += (sender, e) =>
            {
                if (WriteRequested != null)
                {
                    WriteRequested(sender, e);
                }

                if (InterfaceWriteRequested != null)
                {
                    var logEntryData = new UIObjects.LogEntryData
                    {
                        Message = e.LogEntryData.Message,
                        OccuredAt = e.LogEntryData.OccuredAt,
                        LogLevel = (UIObjects.LogLevel) e.LogEntryData.LogLevel,
                        CodeLocation = new UIObjects.CodeLocation
                        {
                            ClassName = e.LogEntryData.CodeLocation.ClassName,
                            FileName = e.LogEntryData.CodeLocation.FileName,
                            LineNumber = e.LogEntryData.CodeLocation.LineNumber,
                            MethodName = e.LogEntryData.CodeLocation.MethodName
                        },
                        ManagedThreadId = e.LogEntryData.ManagedThreadId,
                        Properties = e.LogEntryData.Properties
                    };

                    if (e.LogEntryData.ExceptionMemento != null)
                    {
                        logEntryData.ExceptionMemento = new UIObjects.ExceptionMemento
                        {
                            Message = e.LogEntryData.ExceptionMemento.Message,
                            Source = e.LogEntryData.ExceptionMemento.Source,
                            TypeName = e.LogEntryData.ExceptionMemento.TypeName,
                            StackTrace = e.LogEntryData.ExceptionMemento.StackTrace
                        };
                    }

                    InterfaceWriteRequested(sender, new UIObjects.LogEventArgs(logEntryData));
                }
            };
        }

        public string Name
        {
            get 
            {
                return log.Name;
            }
        }

        public bool DebugEnabled
        {
            get 
			{
				return log.DebugEnabled;
			}
        }

        public bool InfoEnabled
        {
            get 
			{
				return log.InfoEnabled;
			}
        }

        public bool WarnEnabled
        {
            get 
			{
				return log.WarnEnabled;
			}
        }

        public bool ErrorEnabled
        {
            get 
			{
				return log.ErrorEnabled;
			}
        }

        public bool FatalEnabled
        {
            get 
			{
				return log.FatalEnabled;
			}
        }

        public void Debug(string message)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                    log.Debug(message);
                });
            }
        }

        public void Debug(string message, Exception exception)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                    log.Debug(message, exception);
                });
            }
        }

        public void Debug(string message, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Debug(message, properties);
                });
            }
        }

        public void Debug(string message, Exception exception, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Debug(message, exception, properties);
                });
            }
        }

        public void DebugFormat(string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.DebugFormat(message, args);
                });
            }
        }

        public void DebugFormat(IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.DebugFormat(provider, message, args);
                });
            }
        }

        public void DebugFormat(Exception exception, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.DebugFormat(exception, message, args);
                });
            }
        }

        public void DebugFormat(Exception exception, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.DebugFormat(exception, provider, message, args);
                });
            }
        }

        public void DebugFormat(Exception exception, IDictionary<string, object> properties, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.DebugFormat(exception, properties, message, args);
                });
            }
        }

        public void DebugFormat(Exception exception, IDictionary<string, object> properties, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.DebugFormat(exception, properties, provider, message, args);
                });
            }
        }

        public void Info(string message)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Info(message);
                });
            }
        }

        public void Info(string message, Exception exception)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Info(message, exception);
                });
            }
        }

        public void Info(string message, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Info(message, properties);
                });
            }
        }

        public void Info(string message, Exception exception, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Info(message, exception, properties);
                });
            }
        }

        public void InfoFormat(string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                    log.InfoFormat(message, args);
                });
            }
        }

        public void InfoFormat(IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.InfoFormat(provider, message, args);
                });
            }
        }

        public void InfoFormat(Exception exception, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.InfoFormat(exception, message, args);
                });
            }
        }

        public void InfoFormat(Exception exception, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.InfoFormat(exception, provider, message, args);
                });
            }
        }

        public void InfoFormat(Exception exception, IDictionary<string, object> properties, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.InfoFormat(exception, properties, message, args);
                });
            }
        }

        public void InfoFormat(Exception exception, IDictionary<string, object> properties, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.InfoFormat(exception, properties, provider, message, args);
                });
            }
        }

        public void Warn(string message)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Warn(message);
                });
            }
        }

        public void Warn(string message, Exception exception)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Warn(message, exception);
                });
            }
        }

        public void Warn(string message, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Warn(message, properties);
                });
            }
        }

        public void Warn(string message, Exception exception, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Warn(message, exception, properties);
                });
            }
        }

        public void WarnFormat(string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.WarnFormat(message, args);
                });
            }
        }

        public void WarnFormat(IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.WarnFormat(provider, message, args);
                });
            }
        }

        public void WarnFormat(Exception exception, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.WarnFormat(exception, message, args);
                });
            }
        }

        public void WarnFormat(Exception exception, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.WarnFormat(exception, provider, message, args);
                });
            }
        }

        public void WarnFormat(Exception exception, IDictionary<string, object> properties, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.WarnFormat(exception, properties, message, args);
                });
            }
        }

        public void WarnFormat(Exception exception, IDictionary<string, object> properties, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.WarnFormat(exception, properties, provider, message, args);
                });
            }
        }

        public void Error(string message)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Error(message);
                });
            }
        }

        public void Error(string message, Exception exception)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Error(message, exception);
                });
            }
        }

        public void Error(string message, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Error(message, properties);
                });
            }
        }

        public void Error(string message, Exception exception, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Error(message, exception, properties);
                });
            }
        }

        public void ErrorFormat(string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.ErrorFormat(message, args);
                });
            }
        }

        public void ErrorFormat(IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.ErrorFormat(provider, message, args);
                });
            }
        }

        public void ErrorFormat(Exception exception, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.ErrorFormat(exception, message, args);
                });
            }
        }

        public void ErrorFormat(Exception exception, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.ErrorFormat(exception, provider, message, args);
                });
            }
        }

        public void ErrorFormat(Exception exception, IDictionary<string, object> properties, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.ErrorFormat(exception, properties, message, args);
                });
            }
        }

        public void ErrorFormat(Exception exception, IDictionary<string, object> properties, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.ErrorFormat(exception, properties, provider, message, args);
                });
            }
        }

        public void Fatal(string message)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Fatal(message);
                });
            }
        }

        public void Fatal(string message, Exception exception)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Fatal(message, exception);
                });
            }
        }

        public void Fatal(string message, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Fatal(message, properties);
                });
            }
        }

        public void Fatal(string message, Exception exception, IDictionary<string, object> properties)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.Fatal(message, exception, properties);
                });
            }
        }

        public void FatalFormat(string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.FatalFormat(message, args);
                });
            }
        }

        public void FatalFormat(IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.FatalFormat(provider, message, args);
                });
            }
        }

        public void FatalFormat(Exception exception, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.FatalFormat(exception, message, args);
                });
            }
        }

        public void FatalFormat(Exception exception, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.FatalFormat(exception, provider, message, args);
                });
            }
        }

        public void FatalFormat(Exception exception, IDictionary<string, object> properties, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.FatalFormat(exception, properties, message, args);
                });
            }
        }

        public void FatalFormat(Exception exception, IDictionary<string, object> properties, IFormatProvider provider, string message, params object[] args)
        {
            if (Log.Enabled)
            {
                uiThread.Run(() =>
                {
                     log.FatalFormat(exception, properties, provider, message, args);
                });
            }
        }
    }
}
